#include <iostream>
#include <fstream>
#include <iomanip>    // For std::setw, std::fixed, std::setprecision
#include <vector>     // For std::vector
#include <algorithm>  // For std::min, std::max
#include <cmath>      // For fabs

// 包含顶层HLS模块的头文件
#include "gpu_render.hpp"

// 定义屏幕分辨率
#define TEST_SCREEN_WIDTH 1280
#define TEST_SCREEN_HEIGHT 720
#define TOTAL_PIXELS (TEST_SCREEN_WIDTH * TEST_SCREEN_HEIGHT)

// RGB 结构体，用于帧缓冲区
struct RGB {
    unsigned char b, g, r;
};

// 辅助函数：计算三角形的边缘方程系数 (Ax + By + C = 0)
// 注意：这里仍然使用浮点数计算，然后转换为定点数，模拟PS侧的几何处理
void calculate_edge_equations(
    float v0x, float v0y, float v1x, float v1y, float v2x, float v2y,
    fpal::fp_coord_t& A0, fpal::fp_coord_t& B0, fpal::fp_coord_t& C0,
    fpal::fp_coord_t& A1, fpal::fp_coord_t& B1, fpal::fp_coord_t& C1,
    fpal::fp_coord_t& A2, fpal::fp_coord_t& B2, fpal::fp_coord_t& C2
) {
    float cur_A0 = v0y - v1y;
    float cur_B0 = v1x - v0x;
    float cur_C0 = v0x * v1y - v1x * v0y;
    
    float cur_A1 = v1y - v2y;
    float cur_B1 = v2x - v1x;
    float cur_C1 = v1x * v2y - v2x * v1y;

    float cur_A2 = v2y - v0y;
    float cur_B2 = v0x - v2x;
    float cur_C2 = v2x * v0y - v0x * v2y;

    A0 = fpal::to_fp_coord(cur_A0); B0 = fpal::to_fp_coord(cur_B0); C0 = fpal::to_fp_coord(cur_C0);
    A1 = fpal::to_fp_coord(cur_A1); B1 = fpal::to_fp_coord(cur_B1); C1 = fpal::to_fp_coord(cur_C1);
    A2 = fpal::to_fp_coord(cur_A2); B2 = fpal::to_fp_coord(cur_B2); C2 = fpal::to_fp_coord(cur_C2);
}

// 辅助函数：计算深度梯度 (dzdx, dzdy)
// 注意：这里仍然使用浮点数计算，然后转换为定点数，模拟PS侧的几何处理
void calculate_depth_gradients(
    float v0x, float v0y, float v0z, // v0z is 1/Z
    float v1x, float v1y, float v1z,
    float v2x, float v2y, float v2z,
    fpal::fp_coord_t& dzdx, fpal::fp_coord_t& dzdy
) {
    float dx1 = v1x - v0x;
    float dy1 = v1y - v0y;
    float dz1 = v1z - v0z; 

    float dx2 = v2x - v0x;
    float dy2 = v2y - v0y;
    float dz2 = v2z - v0z; 

    float det = dx1 * dy2 - dx2 * dy1;

    if (fabs(det) < 1e-6) { 
        dzdx = fpal::to_fp_coord(0.0f); // 避免直接赋值0，确保类型正确
        dzdy = fpal::to_fp_coord(0.0f);
        return;
    }

    float inv_det = 1.0f / det;
    float _dzdx = (dz1 * dy2 - dz2 * dy1) * inv_det;
    float _dzdy = (dx1 * dz2 - dx2 * dy1) * inv_det;

    dzdx = fpal::to_fp_coord(_dzdx);
    dzdy = fpal::to_fp_coord(_dzdy);
}

// 辅助函数：将 raster_params_packet_fixed 打包成 ap_uint<PACKED_RASTER_PARAMS_BITS>
// 这与 pbirsm.cpp 中的解包操作是逆过程
ap_uint<PACKED_RASTER_PARAMS_BITS> pack_raster_params(const raster_params_packet_fixed& params) {
    ap_uint<PACKED_RASTER_PARAMS_BITS> packed_data;
    int bit_offset = 0;

    // v0_x, v0_y, v1_x, v1_y, v2_x, v2_y (6 * fp_coord_t = 6 * 34 = 204 bits)
    packed_data(bit_offset + 33, bit_offset) = params.v0_x; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.v0_y; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.v1_x; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.v1_y; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.v2_x; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.v2_y; bit_offset += 34;

    // v0_z, v1_z, v2_z (3 * fp_z_buffer_t = 3 * 16 = 48 bits)
    packed_data(bit_offset + 15, bit_offset) = params.v0_z; bit_offset += 16;
    packed_data(bit_offset + 15, bit_offset) = params.v1_z; bit_offset += 16;
    packed_data(bit_offset + 15, bit_offset) = params.v2_z; bit_offset += 16;

    // edge0_A, B, C; edge1_A, B, C; edge2_A, B, C (9 * fp_coord_t = 9 * 34 = 306 bits)
    packed_data(bit_offset + 33, bit_offset) = params.edge0_A; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge0_B; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge0_C; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge1_A; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge1_B; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge1_C; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge2_A; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge2_B; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.edge2_C; bit_offset += 34;

    // dzdx, dzdy (2 * fp_coord_t = 2 * 34 = 68 bits)
    packed_data(bit_offset + 33, bit_offset) = params.dzdx; bit_offset += 34;
    packed_data(bit_offset + 33, bit_offset) = params.dzdy; bit_offset += 34;

    // pure_color_R, G, B (3 * fp_color_channel_t = 3 * 8 = 24 bits)
    packed_data(bit_offset + 7, bit_offset) = params.pure_color_R; bit_offset += 8;
    packed_data(bit_offset + 7, bit_offset) = params.pure_color_G; bit_offset += 8;
    packed_data(bit_offset + 7, bit_offset) = params.pure_color_B; bit_offset += 8;

    return packed_data;
}


// BMP 文件头结构 (14字节)
#pragma pack(push, 1) 
struct BMPFileHeader {
    unsigned short bfType;      
    unsigned int   bfSize;      
    unsigned short bfReserved1; 
    unsigned short bfReserved2; 
    unsigned int   bfOffBits;   
};

// BMP 信息头结构 (40字节)
struct BMPInfoHeader {
    unsigned int   biSize;          
    int            biWidth;         
    int            biHeight;        
    unsigned short biPlanes;        
    unsigned short biBitCount;      
    unsigned int   biCompression;   
    unsigned int   biSizeImage;     
    int            biXPelsPerMeter; 
    unsigned int   biYPelsPerMeter; 
    unsigned int   biClrUsed;       
    unsigned int   biClrImportant;  
};
#pragma pack(pop)

// 辅助函数：将帧缓冲区数据写入BMP文件
void write_bmp(const char* filename, int width, int height, const std::vector<RGB>& framebuffer) {
    std::ofstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "Error: Could not open file " << filename << " for writing." << std::endl;
        return;
    }

    int row_padded_size = (width * 3 + 3) & (~3); 
    int image_size = row_padded_size * height;

    BMPFileHeader file_header;
    file_header.bfType = 0x4D42; 
    file_header.bfSize = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + image_size;
    file_header.bfReserved1 = 0;
    file_header.bfReserved2 = 0;
    file_header.bfOffBits = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);

    BMPInfoHeader info_header;
    info_header.biSize = sizeof(BMPInfoHeader);
    info_header.biWidth = width;
    info_header.biHeight = height; 
    info_header.biPlanes = 1;
    info_header.biBitCount = 24; 
    info_header.biCompression = 0; 
    info_header.biSizeImage = image_size;
    info_header.biXPelsPerMeter = 2835; 
    info_header.biYPelsPerMeter = 2835; 
    info_header.biClrUsed = 0;
    info_header.biClrImportant = 0;

    file.write(reinterpret_cast<char*>(&file_header), sizeof(file_header));
    file.write(reinterpret_cast<char*>(&info_header), sizeof(info_header));
    
    std::vector<unsigned char> row_buffer(row_padded_size);
    for (int y = height - 1; y >= 0; --y) { 
        for (int x = 0; x < width; ++x) {
            row_buffer[x * 3 + 0] = framebuffer[y * width + x].b;
            row_buffer[x * 3 + 1] = framebuffer[y * width + x].g;
            row_buffer[x * 3 + 2] = framebuffer[y * width + x].r;
        }
        file.write(reinterpret_cast<char*>(row_buffer.data()), row_padded_size);
    }

    file.close();
    std::cout << "Successfully wrote " << filename << std::endl;
}


int main() {
    std::cout << "--- GPU_Render Top-Level Module Testbench ---" << std::endl;

    // --- 1. 模拟 DDR 缓冲区 ---
    // DDR_Write_Engine 模块内部的常量，这里为了模拟其行为而重复定义
    const ap_uint<32> Z_PER_WORD = 4; // 64 bits / 16 bits = 4 depth values per word
    const ap_uint<32> COLOR_PER_WORD = 2; // 64 bits / 32 bits = 2 color values per word (assuming 24-bit RGB packed into 32-bit slot)

    const ap_uint<32> num_z_words = 524288; // 匹配 m_axi_gmem_zb_read/write 的 depth
    const ap_uint<32> num_color_words = 524288; // 匹配 m_axi_gmem_fb_write 的 depth
    

    // 由于HLS将zbuffer_ddr_base_addr拆分为读写两个指针，
    // 在C仿真中，我们仍然需要一个单一的物理内存来模拟。
    // 所以这里只声明一个 vector，但逻辑上通过两个指针传递。
    std::vector<zbuffer_ddr_word_t> simulated_zbuffer_ddr_storage(num_z_words);
    std::vector<color_ddr_word_t> simulated_framebuffer_ddr(num_color_words);

    // 两个指针指向同一个内存区域
    zbuffer_ddr_word_t* simulated_zbuffer_ddr_read_ptr = simulated_zbuffer_ddr_storage.data();
    zbuffer_ddr_word_t* simulated_zbuffer_ddr_write_ptr = simulated_zbuffer_ddr_storage.data();


    // 初始化缓冲区
    for (int i = 0; i < num_color_words; ++i) {
        ap_uint<32> default_color_slot = 0x00323232; // 暗灰色背景
        simulated_framebuffer_ddr[i] = ((color_ddr_word_t)default_color_slot << 32) | (color_ddr_word_t)default_color_slot;
    }
    for (int i = 0; i < num_z_words; ++i) {
        simulated_zbuffer_ddr_storage[i] = (ap_uint<64>)0xFFFF'FFFF'FFFF'FFFF; // 全 1 对应 65535 (最远深度)
    }
    std::cout << "[TESTBENCH DEBUG] Initialized Z-buffer with all 65535 (farthest)." << std::endl;


    // --- 2. 准备三角形数据 (用于打包) ---
    // Z值映射逻辑：假设 Z_normalized_float 在 [0.0, 1.0] 范围内，0.0最远，1.0最近。
    // 目标是 fp_z_buffer_t (U.16.0) 的 0 最近，65535 最远。
    auto map_z_to_fp_z_buffer = [](float z_normalized_float) {
        z_normalized_float = fpal::clamp(z_normalized_float, 0.0f, 1.0f);
        fpal::fp_coord_t temp_z_fx = fpal::to_fp_coord((1.0f - z_normalized_float) * 65535.0f);
        fpal::fp_z_buffer_t final_z_val = fpal::to_fp_z_buffer(temp_z_fx);
        // std::cout << "[TESTBENCH DEBUG]   Z_norm: " << z_normalized_float << " -> temp_z_fx: " << temp_z_fx << " -> fp_z_buffer_t: " << final_z_val << std::endl;
        return final_z_val;
    };

    std::vector<raster_params_packet_fixed> test_triangles;

    // ----- 测试用例 1: 简单的直角三角形 (红色) -----
    std::cout << "\n--- Adding Triangle 1 (Red) ---" << std::endl;
    raster_params_packet_fixed tri1;
    float v0x_f=100.0f, v0y_f=100.0f, v0z_f_norm=0.5f; 
    float v1x_f=200.0f, v1y_f=100.0f, v1z_f_norm=0.6f;
    float v2x_f=100.0f, v2y_f=200.0f, v2z_f_norm=0.7f;
    tri1.pure_color_R = fpal::to_fp_color_channel(255); tri1.pure_color_G = fpal::to_fp_color_channel(0); tri1.pure_color_B = fpal::to_fp_color_channel(0);
    tri1.v0_x = fpal::to_fp_coord(v0x_f); tri1.v0_y = fpal::to_fp_coord(v0y_f); tri1.v0_z = map_z_to_fp_z_buffer(v0z_f_norm);
    tri1.v1_x = fpal::to_fp_coord(v1x_f); tri1.v1_y = fpal::to_fp_coord(v1y_f); tri1.v1_z = map_z_to_fp_z_buffer(v1z_f_norm);
    tri1.v2_x = fpal::to_fp_coord(v2x_f); tri1.v2_y = fpal::to_fp_coord(v2y_f); tri1.v2_z = map_z_to_fp_z_buffer(v2z_f_norm);
    calculate_edge_equations(v0x_f, v0y_f, v1x_f, v1y_f, v2x_f, v2y_f, tri1.edge0_A, tri1.edge0_B, tri1.edge0_C, tri1.edge1_A, tri1.edge1_B, tri1.edge1_C, tri1.edge2_A, tri1.edge2_B, tri1.edge2_C);
    calculate_depth_gradients(v0x_f, v0y_f, v0z_f_norm, v1x_f, v1y_f, v1z_f_norm, v2x_f, v2y_f, v2z_f_norm, tri1.dzdx, tri1.dzdy);
    test_triangles.push_back(tri1);

    // ----- 测试用例 2: 扁平的水平三角形 (蓝色), 部分覆盖Case 1，Z值更近 -----
    std::cout << "\n--- Adding Triangle 2 (Blue) ---" << std::endl;
    raster_params_packet_fixed tri2;
    v0x_f = 120.0f, v0y_f = 110.0f, v0z_f_norm = 0.8f; 
    v1x_f = 250.0f, v1y_f = 110.0f, v1z_f_norm = 0.85f; 
    v2x_f = 185.0f, v2y_f = 130.0f, v2z_f_norm = 0.9f;  
    tri2.pure_color_R = fpal::to_fp_color_channel(0); tri2.pure_color_G = fpal::to_fp_color_channel(0); tri2.pure_color_B = fpal::to_fp_color_channel(255);
    tri2.v0_x = fpal::to_fp_coord(v0x_f); tri2.v0_y = fpal::to_fp_coord(v0y_f); tri2.v0_z = map_z_to_fp_z_buffer(v0z_f_norm);
    tri2.v1_x = fpal::to_fp_coord(v1x_f); tri2.v1_y = fpal::to_fp_coord(v1y_f); tri2.v1_z = map_z_to_fp_z_buffer(v1z_f_norm); 
    tri2.v2_x = fpal::to_fp_coord(v2x_f); tri2.v2_y = fpal::to_fp_coord(v2y_f); tri2.v2_z = map_z_to_fp_z_buffer(v2z_f_norm);
    calculate_edge_equations(v0x_f, v0y_f, v1x_f, v1y_f, v2x_f, v2y_f, tri2.edge0_A, tri2.edge0_B, tri2.edge0_C, tri2.edge1_A, tri2.edge1_B, tri2.edge1_C, tri2.edge2_A, tri2.edge2_B, tri2.edge2_C);
    calculate_depth_gradients(v0x_f, v0y_f, v0z_f_norm, v1x_f, v1y_f, v1z_f_norm, v2x_f, v2y_f, v2z_f_norm, tri2.dzdx, tri2.dzdy);
    test_triangles.push_back(tri2);
    
    // ----- 测试用例 3: 部分在屏幕外的三角形 (绿色), Z值比Case 1更远 -----
    std::cout << "\n--- Adding Triangle 3 (Green) ---" << std::endl;
    raster_params_packet_fixed tri3;
    v0x_f = -50.0f, v0y_f = -50.0f, v0z_f_norm = 0.1f;
    v1x_f = 100.0f, v1y_f = 0.0f, v1z_f_norm = 0.2f;
    v2x_f = 0.0f, v2y_f = 100.0f, v2z_f_norm = 0.3f;
    tri3.pure_color_R = fpal::to_fp_color_channel(0); tri3.pure_color_G = fpal::to_fp_color_channel(255); tri3.pure_color_B = fpal::to_fp_color_channel(0);
    tri3.v0_x = fpal::to_fp_coord(v0x_f); tri3.v0_y = fpal::to_fp_coord(v0y_f); tri3.v0_z = map_z_to_fp_z_buffer(v0z_f_norm);
    tri3.v1_x = fpal::to_fp_coord(v1x_f); tri3.v1_y = fpal::to_fp_coord(v1y_f); tri3.v1_z = map_z_to_fp_z_buffer(v1z_f_norm);
    tri3.v2_x = fpal::to_fp_coord(v2x_f); tri3.v2_y = fpal::to_fp_coord(v2y_f); tri3.v2_z = map_z_to_fp_z_buffer(v2z_f_norm);
    calculate_edge_equations(v0x_f, v0y_f, v1x_f, v1y_f, v2x_f, v2y_f, tri3.edge0_A, tri3.edge0_B, tri3.edge0_C, tri3.edge1_A, tri3.edge1_B, tri3.edge1_C, tri3.edge2_A, tri3.edge2_B, tri3.edge2_C);
    calculate_depth_gradients(v0x_f, v0y_f, v0z_f_norm, v1x_f, v1y_f, v1z_f_norm, v2x_f, v2y_f, v2z_f_norm, tri3.dzdx, tri3.dzdy);
    test_triangles.push_back(tri3);

    // ----- 测试用例 4: 一个覆盖大部分屏幕的黄色三角形，Z值在中间 -----
    std::cout << "\n--- Adding Triangle 4 (Yellow) ---" << std::endl;
    raster_params_packet_fixed tri4;
    v0x_f = 0.0f, v0y_f = 0.0f, v0z_f_norm = 0.4f;
    v1x_f = 1279.0f, v1y_f = 0.0f, v1z_f_norm = 0.45f;
    v2x_f = 640.0f, v2y_f = 719.0f, v2z_f_norm = 0.5f;
    tri4.pure_color_R = fpal::to_fp_color_channel(255); tri4.pure_color_G = fpal::to_fp_color_channel(255); tri4.pure_color_B = fpal::to_fp_color_channel(0); 
    tri4.v0_x = fpal::to_fp_coord(v0x_f); tri4.v0_y = fpal::to_fp_coord(v0y_f); tri4.v0_z = map_z_to_fp_z_buffer(v0z_f_norm);
    tri4.v1_x = fpal::to_fp_coord(v1x_f); tri4.v1_y = fpal::to_fp_coord(v1y_f); tri4.v1_z = map_z_to_fp_z_buffer(v1z_f_norm);
    tri4.v2_x = fpal::to_fp_coord(v2x_f); tri4.v2_y = fpal::to_fp_coord(v2y_f); tri4.v2_z = map_z_to_fp_z_buffer(v2z_f_norm);
    calculate_edge_equations(v0x_f, v0y_f, v1x_f, v1y_f, v2x_f, v2y_f, tri4.edge0_A, tri4.edge0_B, tri4.edge0_C, tri4.edge1_A, tri4.edge1_B, tri4.edge1_C, tri4.edge2_A, tri4.edge2_B, tri4.edge2_C);
    calculate_depth_gradients(v0x_f, v0y_f, v0z_f_norm, v1x_f, v1y_f, v1z_f_norm, v2x_f, v2y_f, v2z_f_norm, tri4.dzdx, tri4.dzdy);
    test_triangles.push_back(tri4);

    // ----- 测试用例 5: 完全在屏幕外的品红色三角形 (不应渲染任何像素) -----
    std::cout << "\n--- Adding Triangle 5 (Magenta) ---" << std::endl;
    raster_params_packet_fixed tri5;
    v0x_f = -200.0f, v0y_f = -200.0f, v0z_f_norm = 0.1f;
    v1x_f = -150.0f, v1y_f = -180.0f, v1z_f_norm = 0.15f;
    v2x_f = -100.0f, v2y_f = -150.0f, v2z_f_norm = 0.2f;
    tri5.pure_color_R = fpal::to_fp_color_channel(255); tri5.pure_color_G = fpal::to_fp_color_channel(0); tri5.pure_color_B = fpal::to_fp_color_channel(255); 
    tri5.v0_x = fpal::to_fp_coord(v0x_f); tri5.v0_y = fpal::to_fp_coord(v0y_f); tri5.v0_z = map_z_to_fp_z_buffer(v0z_f_norm);
    tri5.v1_x = fpal::to_fp_coord(v1x_f); tri5.v1_y = fpal::to_fp_coord(v1y_f); tri5.v1_z = map_z_to_fp_z_buffer(v1z_f_norm);
    tri5.v2_x = fpal::to_fp_coord(v2x_f); tri5.v2_y = fpal::to_fp_coord(v2y_f); tri5.v2_z = map_z_to_fp_z_buffer(v2z_f_norm);
    calculate_edge_equations(v0x_f, v0y_f, v1x_f, v1y_f, v2x_f, v2y_f, tri5.edge0_A, tri5.edge0_B, tri5.edge0_C, tri5.edge1_A, tri5.edge1_B, tri5.edge1_C, tri5.edge2_A, tri5.edge2_B, tri5.edge2_C);
    calculate_depth_gradients(v0x_f, v0y_f, v0z_f_norm, v1x_f, v1y_f, v1z_f_norm, v2x_f, v2y_f, v2z_f_norm, tri5.dzdx, tri5.dzdy);
    test_triangles.push_back(tri5);

    // 确定发送了多少个三角形
    const ap_uint<16> num_triangles_to_process = test_triangles.size(); 

    // --- 3. 准备 PBIRSM 的模拟 DDR 输入 ---
    // 计算 PBIRSM 的 DDR 缓冲区所需大小
    const ap_uint<32> num_ddr_words_for_params = num_triangles_to_process * NUM_AXI_WORDS_PER_PACKET;
    std::vector<ddr_word_t> simulated_params_ddr(num_ddr_words_for_params);

    // 将所有测试三角形数据打包并写入模拟 DDR
    std::cout << "\nPacking triangle parameters and writing to simulated DDR for PBIRSM..." << std::endl;
    for (int i = 0; i < num_triangles_to_process; ++i) {
        ap_uint<PACKED_RASTER_PARAMS_BITS> packed_data = pack_raster_params(test_triangles[i]);
        // 将 packed_data 分割成 64 位字，写入 simulated_params_ddr
        for (int j = 0; j < NUM_AXI_WORDS_PER_PACKET; ++j) {
            simulated_params_ddr[i * NUM_AXI_WORDS_PER_PACKET + j] = 
                packed_data( (j + 1) * AXI_STREAM_WORD_BITS - 1, j * AXI_STREAM_WORD_BITS );
        }
    }
    std::cout << "Finished packing " << num_triangles_to_process << " triangles into simulated DDR." << std::endl;
    
    // --- 4. 调用顶层 GPU_Render 模块 ---

    ap_uint<32> actual_fragments_from_hr = 0;
    ap_uint<32> actual_write_ops_from_dwe = 0;

    std::cout << "\nCalling GPU_Render top-level module..." << std::endl;
    GPU_Render(
        simulated_params_ddr.data(),             // params_buffer_base_addr (M_AXI_HP0)
        num_triangles_to_process,                // num_triangles_to_process
        (ap_uint<11>)TEST_SCREEN_WIDTH,          // max_x_res
        (ap_uint<11>)TEST_SCREEN_HEIGHT,         // max_y_res
        simulated_zbuffer_ddr_read_ptr,          // zbuffer_ddr_read_base_addr (M_AXI_HP1)
        simulated_zbuffer_ddr_write_ptr,         // zbuffer_ddr_write_base_addr (M_AXI_HP2)
        simulated_framebuffer_ddr.data(),        // framebuffer_ddr_base_addr (M_AXI_HP3)
        actual_fragments_from_hr,                // total_fragments_generated (HR Output)
        actual_write_ops_from_dwe                // total_write_ops_processed (DWE Output)
    );
    std::cout << "GPU_Render top-level module finished." << std::endl;

    std::cout << "\n------------------------------------" << std::endl;
    std::cout << "Overall Rasterization Result:" << std::endl;
    std::cout << "HR reported total fragments generated: " << actual_fragments_from_hr << std::endl;
    std::cout << "DDR_Write_Engine processed write operations: " << actual_write_ops_from_dwe << std::endl;
    std::cout << "------------------------------------" << std::endl;

    // --- 5. 将模拟DDR中的帧缓冲区数据转换为RGB格式并写入BMP文件 ---
    std::vector<RGB> final_framebuffer(TOTAL_PIXELS);
    for (int i = 0; i < TOTAL_PIXELS; ++i) {
        ap_uint<32> color_word_idx = i / COLOR_PER_WORD;
        ap_uint<1> color_sub_word_offset = i % COLOR_PER_WORD;

        color_ddr_word_t full_word = simulated_framebuffer_ddr[color_word_idx];
        ap_uint<32> packed_pixel_color;

        if (color_sub_word_offset == 0) { 
            packed_pixel_color = (ap_uint<32>)(full_word & 0xFFFFFFFF);
        } else { 
            packed_pixel_color = (ap_uint<32>)((full_word >> 32) & 0xFFFFFFFF);
        }
        
        final_framebuffer[i].b = (unsigned char)(packed_pixel_color & 0xFF);
        final_framebuffer[i].g = (unsigned char)((packed_pixel_color >> 8) & 0xFF);
        final_framebuffer[i].r = (unsigned char)((packed_pixel_color >> 16) & 0xFF);
    }

    write_bmp("raster_output_combined.bmp", TEST_SCREEN_WIDTH, TEST_SCREEN_HEIGHT, final_framebuffer);

    return 0;
}
